<template>
  <div>
    <div> <!-- 按钮 -->
      <button @click="recOpen">打开录音,请求权限</button>
      | <button @click="recStart">开始录音</button>
      <button @click="recStop">结束录音</button>
      | <button @click="recPlay">本地试听</button>
      | <button @click="recClose">关闭录音，释放资源</button>
    </div>
    <div style="padding-top:5px"> <!-- 波形绘制区域 -->
      <div style="border:1px solid #ccc;display:inline-block;vertical-align:bottom">
        <div style="height:100px;width:300px;" ref="recwave"></div>
      </div>
    </div>
  </div>
</template>


<script>
//必须引入的核心
import Recorder from 'recorder-core'
import 'recorder-core/src/engine/beta-amr'
import 'recorder-core/src/engine/beta-amr-engine'
//引入mp3格式支持文件；如果需要多个格式支持，把这些格式的编码引擎js文件放到后面统统引入进来即可
import 'recorder-core/src/engine/mp3'
import 'recorder-core/src/engine/mp3-engine'

export default {
  name: 'Login',
  data() {
    return {
      rec: Object,
      recBlob: Object,
      realTimeSendTryType: 'pcm',
      realTimeSendTryEncBusy: 0,
      realTimeSendTryTime: 0,
      realTimeSendTryNumber: 0,
      transferUploadNumberMax: 0,
      realTimeSendTryChunk: null,
      bufferMax:20
    }
  },
  methods: {
    RealTimeSendTry(buffers, bufferSampleRate, isClose) {
      var t1 = Date.now();
      if (this.realTimeSendTryTime == 0) {
        this.realTimeSendTryTime = t1;
        this.realTimeSendTryEncBusy = 0;
        this.realTimeSendTryNumber = 0;
        this.transferUploadNumberMax = 0;
        this.realTimeSendTryChunk = null;
      };
      console.log("buffers.length", buffers.length, "bufferSampleRate", bufferSampleRate, "isClose", isClose, "this.realTimeSendTryTime", this.realTimeSendTryTime, "t1", t1, "this.realTimeSendTryEncBusy", this.realTimeSendTryEncBusy, "this.realTimeSendTryNumber", this.realTimeSendTryNumber, "this.transferUploadNumberMax")
      if (!isClose && buffers.length < this.bufferMax) {
        return;//控制缓冲达到指定间隔才进行传输
      };
      this.realTimeSendTryTime = t1;
      var number = ++this.realTimeSendTryNumber;

      var pcm = [], pcmSampleRate = 0;
      if (buffers.length > 0) {
        //借用SampleData函数进行数据的连续处理，采样率转换是顺带的，得到新的pcm数据
        var chunk = Recorder.SampleData(buffers, bufferSampleRate, 8000, this.realTimeSendTryChunk, { frameType: isClose ? "" : this.realTimeSendTryType });

        //清理已处理完的缓冲数据，释放内存以支持长时间录音，最后完成录音时不能调用stop，因为数据已经被清掉了
        for (var i = this.realTimeSendTryChunk ? this.realTimeSendTryChunk.index : 0; i < chunk.index; i++) {
          buffers[i] = null;
        };
        this.realTimeSendTryChunk = chunk;//此时的chunk.data就是原始的音频16位pcm数据（小端LE），直接保存即为16位pcm文件、加个wav头即为wav文件、丢给mp3编码器转一下码即为mp3文件

        pcm = chunk.data;
        pcmSampleRate = chunk.sampleRate;
      };

      //没有新数据，或结束时的数据量太小，不能进行mock转码
      if (pcm.length == 0 || isClose && pcm.length < 2000) {
        TransferUpload(number, null, 0, null, isClose);
        return;
      };

      //实时编码队列阻塞处理
      if (!isClose) {
        if (this.realTimeSendTryEncBusy >= 2) {
          console.log("编码队列阻塞，已丢弃一帧", 1);
          return;
        };
      };
      this.realTimeSendTryEncBusy++;

      //通过mock方法实时转码成mp3、wav；16位pcm格式可以不经过此操作，直接发送new Blob([pcm.buffer],{type:"audio/pcm"}) 要8位的就必须转码
      var encStartTime = Date.now();
      var recMock = Recorder({
        type: "amr" //录音格式，可以换成wav等其他格式
        , sampleRate: 8000 //录音的采样率，越大细节越丰富越细腻
        , bitRate: 12.2 //录音的比特率，越大音质越好
      });
      recMock.mock(pcm, pcmSampleRate);
      let that = this
      recMock.stop(function (blob, duration) {
        that.realTimeSendTryEncBusy && (that.realTimeSendTryEncBusy--);
        blob.encTime = Date.now() - encStartTime;

        //转码好就推入传输
        TransferUpload(number, blob, duration, recMock, isClose);
      }, function (msg) {
        that.realTimeSendTryEncBusy && (that.realTimeSendTryEncBusy--);

        //转码错误？没想到什么时候会产生错误！
       console.log("不应该出现的错误:" + msg, 1);
      });

      
    },
    TransferUpload(number, blobOrNull, duration, blobRec, isClose) {
      this.transferUploadNumberMax = Math.max(this.transferUploadNumberMax, number);
      if (blobOrNull) {
        var blob = blobOrNull;
        var encTime = blob.encTime;

        //*********发送方式一：Base64文本发送***************
        var reader = new FileReader();
        reader.onloadend = function () {
          var base64 = (/.+;\s*base64\s*,\s*(.+)$/i.exec(reader.result) || [])[1];

          //可以实现
          //WebSocket send(base64) ...
          //WebRTC send(base64) ...
          //XMLHttpRequest send(base64) ...

          //这里啥也不干
        };
        reader.readAsDataURL(blob);

        //*********发送方式二：Blob二进制发送***************
        //可以实现
        //WebSocket send(blob) ...
        //WebRTC send(blob) ...
        //XMLHttpRequest send(blob) ...


        //****这里仅 console.log一下 意思意思****
        var numberFail = number < this.transferUploadNumberMax ? '<span style="color:red">顺序错乱的数据，如果要求不高可以直接丢弃，或者调大SendInterval试试</span>' : "";
        var logMsg = "No." + (number < 100 ? ("000" + number).substr(-3) : number) + numberFail;

        console.log(blob, duration, blobRec, logMsg + "花" + ("___" + encTime).substr(-3) + "ms");

        // if (true && number % 100 == 0) {//emmm....
        //   Runtime.LogClear();
        // };
      };

      if (isClose) {
        console.log("No." + (number < 100 ? ("000" + number).substr(-3) : number) + ":已停止传输");
      };
    },
    RealTimeSendTryReset(){
      this.realTimeSendTryType="pcm";
      this.realTimeSendTryTime=0;
    },
    recOpen() {
      let that = this;
      this.rec = Recorder({
        type:"unknown"
        , onProcess: (buffers, powerLevel, bufferDuration, bufferSampleRate, newBufferIdx, asyncEnd) => {
          // Runtime.Process.apply(null,arguments);
			
			  //推入实时处理，因为是unknown格式，buffers和rec.buffers是完全相同的（此时采样率为浏览器采集音频的原始采样率），只需清理buffers就能释放内存，其他格式不一定有此特性。
			  that.RealTimeSendTry(buffers,bufferSampleRate,false);
        }
      });

      //打开录音，获得权限
      this.rec.open(() => {
        console.log("录音已打开");
        // if (this.$refs.recwave) {//创建音频可视化图形绘制对象
        //   this.wave = Recorder.WaveView({ elem: this.$refs.recwave });
        // }
      }, (msg, isUserNotAllow) => {
        //用户拒绝了录音权限，或者浏览器不支持录音
        console.log((isUserNotAllow ? "UserNotAllow，" : "") + "无法录音:" + msg);
      });
      that.RealTimeSendTryReset();//重置环境，开始录音时必须调用一次
    }, 
    recStart() {
      if (!this.rec) { console.error("未打开录音"); return }
      this.rec.start();
      console.log("已开始录音");
    },
    recStop() {
      this.rec.close();//关闭录音，释放录音资源，当然可以不释放，后面可以连续调用start
      this.RealTimeSendTry([],0,true);//最后一次发送
    },
    recPlay() {
      //本地播放录音试听，可以直接用URL把blob转换成本地播放地址，用audio进行播放
      var localUrl = URL.createObjectURL(this.recBlob);
      var audio = document.createElement("audio");
      audio.controls = true;
      document.body.appendChild(audio);
      audio.src = localUrl;
      audio.play(); //这样就能播放了

      //注意不用了时需要revokeObjectURL，否则霸占内存
      setTimeout(function () { URL.revokeObjectURL(audio.src) }, 5000);
    },
    recClose() {
      if (!this.rec) { console.error("未打开录音"); return }
      this.rec.close()
      console.log("关闭录音，释放资源")
    }

  }
}
</script>

<style lang="scss"></style>
